package com.google.code.v8config;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;

public final class Image {

    //--------------------------------------------------------------------------
    private final long CMD_INDEX_NULL = 0xffffffffL;

    private final int VAR_OPTION_LOCAL = 0x00000001;
    private final int VAR_OPTION_EXTERNAL = 0x00000002;
    private final int VAR_OPTION_PARAMETER = 0x00000004;
    private final int VAR_OPTION_VALUE = 0x00000008;
    private final int VAR_OPTION_EXPORT = 0x00000010;

    private final int PROC_OPTION_FUNCTION = 0x00000001;
    private final int PROC_OPTION_EXPORT = 0x00000010;
    private final int PROC_OPTION_EXTERNAL = 0x00000020;

    private final String STRING_LINE_FEED = "\r\n";
    private final String STRING_LINE_INDENT = "\t";
    
    //--------------------------------------------------------------------------
    private final class Command {

        //----------------------------------------------------------------------
        private int m_Command;
        private int m_Parameter;

        //----------------------------------------------------------------------
        public Command(int command, int parameter) {
            setCommand(command);
            setParameter(parameter);
        }
        //----------------------------------------------------------------------
        public int getCommand() {
            return m_Command;
        }
        public void setCommand(int value) {
            m_Command = value;
        }

        public int getParameter() {
            return m_Parameter;
        }
        public void setParameter(int value) {
            m_Parameter = value;
        }

        @Override
        public String toString() {
            return "{"+getCommand()+","+getParameter()+"}";
        }
        
        //----------------------------------------------------------------------
    }
    private final class Constant {

        //----------------------------------------------------------------------
        private String m_Type;
        private String m_Value;

        //----------------------------------------------------------------------
        public Constant(String type, String value) {
            setType(type);
            setValue(value);
        }

        //----------------------------------------------------------------------
        public String getType() {
            return m_Type;
        }
        public void setType(String value) {
            m_Type = value;
        }

        public String getValue() {
            return m_Value;
        }
        public void setValue(String value) {
            m_Value = value;
        }

        @Override
        public String toString() {
            return "{"+getType()+","+getValue()+"}";
        }

        //----------------------------------------------------------------------
    }
    private final class Variable {

        //----------------------------------------------------------------------
        private String m_Name;
        private int m_Options;
        private int m_Reserved0;
        
        //----------------------------------------------------------------------
        public Variable(String name, int options, int reserved0) {
            setName(name);
            setOptions(options);
            setReserved0(reserved0);
        }

        //----------------------------------------------------------------------
        public String getName() {
            return m_Name;
        }
        public void setName(String value) {
            m_Name = value;
        }

        public int getOptions() {
            return m_Options;
        }
        public void setOptions(int value) {
            m_Options = value;
        }

        public int getReserved0() {
            return m_Reserved0;
        }
        public void setReserved0(int value) {
            m_Reserved0 = value;
        }

        @Override
        public String toString() {
            return "{"+getName()+","+getOptions()+","+getReserved0()+"}";
        }

        //----------------------------------------------------------------------
    }
    private final class Label {

        //----------------------------------------------------------------------
        private String m_Name;
        private int m_CommandIndex;

        //----------------------------------------------------------------------
        public Label(String name, int cmdIndex) {
            setName(name);
            setCommandIndex(cmdIndex);
        }

        //----------------------------------------------------------------------
        public String getName() {
            return m_Name;
        }
        public void setName(String value) {
            m_Name = value;
        }

        public int getCommandIndex() {
            return m_CommandIndex;
        }
        public void setCommandIndex(int value) {
            m_CommandIndex = value;
        }

        @Override
        public String toString() {
            return "{"+getName()+","+getCommandIndex()+"}";
        }

        //----------------------------------------------------------------------
    }
    private final class Procedure {

        //----------------------------------------------------------------------
        private String m_Name;
        private int m_Options;
        private int m_ParameterCount;
        private int m_FirstCommandIndex;
        private List<Label> m_Labels = new ArrayList<Label>();
        private List<Variable> m_Variables = new ArrayList<Variable>();
        private List<Constant> m_DefinedParameters = new ArrayList<Constant>();

        //----------------------------------------------------------------------
        public Procedure(String name, int options, int prmCount, int firstCmdIndex) {
            setName(name);
            setOptions(options);
            setParameterCount(prmCount);
            setFirstCommandIndex(firstCmdIndex);
        }

        //----------------------------------------------------------------------
        public String getName() {
            return m_Name;
        }
        public void setName(String value) {
            m_Name = value;
        }

        public int getOptions() {
            return m_Options;
        }
        public void setOptions(int value) {
            m_Options = value;
        }

        public int getParameterCount() {
            return m_ParameterCount;
        }
        public void setParameterCount(int value) {
            m_ParameterCount = value;
        }

        public int getFirstCommandIndex() {
            return m_FirstCommandIndex;
        }
        public void setFirstCommandIndex(int value) {
            m_FirstCommandIndex = value;
        }

        public List<Label> getLabels() {
            return m_Labels;
        }
        public List<Variable> getVariables() {
            return m_Variables;
        }
        public List<Constant> getDefinedParameters() {
            return m_DefinedParameters;
        }

        @Override
        public String toString() {
            return "{"+getName()+","+getOptions()+","+getParameterCount()+"}";
        }

        //----------------------------------------------------------------------
    }

    private final class SourceBlock {

        //----------------------------------------------------------------------
        public final class Line {

            //------------------------------------------------------------------
            private String m_String;
            private int m_CommandIndex;

            //------------------------------------------------------------------
            public Line(String string, int commandIndex) {
                setString(string);
                setCommandIndex(commandIndex);
            }

            //------------------------------------------------------------------
            public String getString() {
                return m_String;
            }
            public void setString(String string) {
                m_String = string;
            }

            public int getCommandIndex() {
                return m_CommandIndex;
            }
            public void setCommandIndex(int commandIndex) {
                m_CommandIndex = commandIndex;
            }

            @Override
            public String toString() {
                return getString();
            }
            
            //------------------------------------------------------------------
        }
        
        //----------------------------------------------------------------------
        private List<Line> m_Lines = new LinkedList<Line>();
        private int m_LastJump = -1;

        //----------------------------------------------------------------------
        public List<Line> getLines() {
            return m_Lines;
        }

        public int getLastJump() {
            return m_LastJump;
        }
        public void setLastJump(int value) {
            m_LastJump = value;
        }

        public void addLine(String str, int commandIndex) {
            getLines().add(new Line(str, commandIndex));
            if(commandIndex>=0)
                setLastJump(commandIndex);
        }
        public void addLine(String str) {
            addLine(str, -1);
        }

        public void insertLine(int index, String str) {
            getLines().add(index, new Line(str, -1));
        }

        public Line removeLastLine() {
            return getLines().remove(getLines().size()-1);
        }

        public void checkJumps(int blockBegin, int blockEnd, boolean cycle) {
            for(Line line : getLines()) {
                int cmdIndex = line.getCommandIndex();
                if(cmdIndex>0) {
                    String jump = null;
                    if(cycle) {
                        if(cmdIndex==blockEnd+1)
                            jump = getDictionary().getString("break"); 
                        else if(cmdIndex<=blockEnd)
                            jump = getDictionary().getString("continue");
                    } else
                        jump = getDictionary().getString("return");
                    if(jump!=null) {
                        line.setString(line.getString()+jump+";");
                        line.setCommandIndex(-1);
                    }
                }
            }
        }

        //----------------------------------------------------------------------
    }

    //--------------------------------------------------------------------------
    public static ResourceBundle getDictionary(Locale locale) {
        
        if(locale==null)
            locale = Locale.getDefault();
        
        String resourceName = Image.class.getPackage().getName() + ".Dictionary";
        return ResourceBundle.getBundle(resourceName, locale);
    }
    
    //--------------------------------------------------------------------------
    private int m_Reserved0;
    private long m_BodyFirstCommandIndex;
    private final List<Command> m_Commands = new ArrayList<Command>();
    private final List<Constant> m_Constants = new ArrayList<Constant>();
    private final List<Variable> m_Variables = new ArrayList<Variable>();
    private final List<Label> m_Labels = new ArrayList<Label>();
    private final List<Procedure> m_Procedures = new ArrayList<Procedure>();

    private ResourceBundle m_Dictionary;
    
    //--------------------------------------------------------------------------
    public Image() {
        //
    }

    //--------------------------------------------------------------------------
    private int getReserved0() {
        return m_Reserved0;
    }
    private void setReserved0(int value) {
        m_Reserved0 = value;
    }

    private long getBodyFirstCommandIndex() {
        return m_BodyFirstCommandIndex;
    }
    private void setBodyFirstCommandIndex(long commandIndex) {
        m_BodyFirstCommandIndex = commandIndex;
    }

    private List<Command> getCommands() {
        return m_Commands;
    }
    private List<Constant> getConstants() {
        return m_Constants;
    }
    private List<Variable> getVariables() {
        return m_Variables;
    }
    private List<Label> getLabels() {
        return m_Labels;
    }
    private List<Procedure> getProcedures() {
        return m_Procedures;
    }

    private ResourceBundle getDictionary() {
        return m_Dictionary;
    }
    private void setDictionary(ResourceBundle dictionary) {
        m_Dictionary = dictionary;
    }

    //--------------------------------------------------------------------------
    public void restoreSource(File dir, ResourceBundle dictionary) 
            throws IOException {
        
        File imageFile = new File(dir+FileUtils.FILE_SEPARATOR+"image");
        if(!imageFile.exists())
            throw new IOException("Image file not exists");
        File infoFile = new File(dir+FileUtils.FILE_SEPARATOR+"info");
        if(!infoFile.exists())
            throw new IOException("Info file not exists");

        // load
        DataList image = FileUtils.readFileAsDataList(imageFile);
        DataList info = FileUtils.readFileAsDataList(infoFile);
        load(image, dictionary);
        
        // prepare
        String text = disassemble();
        info.get(1).setString("1");
        
        // save
        if(!imageFile.delete())
            throw new IOException("Cannot delete image file");
        File textFile = new File(dir+FileUtils.FILE_SEPARATOR+"text");
        FileUtils.writeFile(textFile, text);
        FileUtils.writeFile(infoFile, info);
        
    }
    private void load(DataList datalist, ResourceBundle dictionary)
            throws IOException {

        // init
        m_Reserved0 = 0;
        m_BodyFirstCommandIndex = 0;
        m_Commands.clear();
        m_Constants.clear();
        m_Variables.clear();
        m_Labels.clear();
        m_Procedures.clear();
        m_Dictionary = null;
    
        if(datalist.getCount()>=2
                && datalist.get(1).getList().get(0).getString().equals("\"Cmd\"")) {

            setReserved0(Integer.parseInt(datalist.get(0).getString()));

            int position = 1;
            if(readCommands(datalist.get(position).getList()))
                position++;
            if(position<datalist.getCount() && readConstants(datalist.get(position).getList(), null))
                position++;
            if(position<datalist.getCount() && readVariables(datalist.get(position).getList(), null))
                position++;
            if(position<datalist.getCount() && readProcedures(datalist.get(position).getList()))
                position++;

            if(position!=datalist.getCount())
                throw new IOException("Wrong datalist format");
        } else
            throw new IOException("Datalist is not image");
        
        setDictionary(dictionary);
        
    }    
    private String disassemble()
            throws IOException {

        StringBuilder strBuilder = new StringBuilder();
        strBuilder.appendCodePoint(FileUtils.DATA_PREFIX);

        // Variables
        for(Variable var : getVariables())
            if((var.getOptions()&VAR_OPTION_EXTERNAL)==0) {
                String keyvar = getDictionary().getString("var");
                strBuilder.append(keyvar);
                strBuilder.append(" ");
                strBuilder.append(var.getName());
                if((var.getOptions()&VAR_OPTION_EXPORT)!=0) {
                    strBuilder.append(" ");
                    String keyexport = getDictionary().getString("export");
                    strBuilder.append(keyexport);
                }
                strBuilder.append(";");
                strBuilder.append(STRING_LINE_FEED);
            }

        // Methods
        for(Procedure procedure : getProcedures())
            if((procedure.getOptions()&PROC_OPTION_EXTERNAL)==0) {
                //System.out.println(proc.getName());
                int blockBegin = procedure.getFirstCommandIndex();
                int blockEnd = -1;
                for(int i=procedure.getFirstCommandIndex(); i<getCommands().size(); i++)
                    if(getCommands().get(i).getCommand()==22) {
                        blockEnd = i;
                        break;
                    }
                if(blockEnd==-1)
                    throw new IOException("End of method not found");
                
                SourceBlock block = disassembleBlock(blockBegin, blockEnd, procedure, false);

                // writing method header
                strBuilder.append(STRING_LINE_FEED);
                String keymethod = (procedure.getOptions()&PROC_OPTION_FUNCTION)!=0 ? 
                    getDictionary().getString("function") : getDictionary().getString("procedure");
                strBuilder.append(keymethod);
                strBuilder.append(" ");
                strBuilder.append(procedure.getName());
                strBuilder.append("(");
                for(int j=0; j<procedure.getParameterCount(); j++) {
                    Variable var = procedure.getVariables().get(j);

                    if((var.getOptions()&VAR_OPTION_PARAMETER)==0)
                        throw new IOException("Var is not parameter");

                    if(j>0)
                        strBuilder.append(",");
                    if((var.getOptions()&VAR_OPTION_VALUE)!=0) {
                        String keyval = getDictionary().getString("val");
                        strBuilder.append(keyval);
                        strBuilder.append(" ");
                    }
                    strBuilder.append(var.getName());
                    if(j<procedure.getDefinedParameters().size()) {
                        Constant defprm = procedure.getDefinedParameters().get(j);
                        if(!defprm.getType().equals("")) {
                            strBuilder.append("=");
                            strBuilder.append(getConstantValue(defprm));
                        }
                    }
                }
                strBuilder.append(")");
                if((procedure.getOptions()&PROC_OPTION_EXPORT)!=0) {
                    strBuilder.append(" ");
                    String keyexport = getDictionary().getString("export");
                    strBuilder.append(keyexport);
                }
                strBuilder.append(STRING_LINE_FEED);

                // writing method body
                block.checkJumps(blockBegin, blockEnd, false);
                for(SourceBlock.Line line : block.getLines()) {
                    strBuilder.append(makeIndent(line.getString()));
                    strBuilder.append(STRING_LINE_FEED);
                }

                // writing method footer
                String keyendmethod = (procedure.getOptions()&PROC_OPTION_FUNCTION)!=0 ?
                    getDictionary().getString("endfunction") : getDictionary().getString("endprocedure");
                strBuilder.append(keyendmethod);
                strBuilder.append(STRING_LINE_FEED);
            }

        // Module init body
        if(getBodyFirstCommandIndex()!=CMD_INDEX_NULL) {
            strBuilder.append(STRING_LINE_FEED);
            int blockBegin = (int)getBodyFirstCommandIndex();
            int blockEnd = getCommands().size()-1;
            SourceBlock block = disassembleBlock(blockBegin, blockEnd, null, false);
            block.checkJumps(blockBegin, blockEnd, false);
            for(SourceBlock.Line line : block.getLines()) {
                strBuilder.append(line.getString());
                strBuilder.append(STRING_LINE_FEED);
            }
        }

        //System.out.println(strBuilder.toString());
        return strBuilder.toString();
    }

    //--------------------------------------------------------------------------
    private boolean readCommands(DataList datalist)
            throws IOException {

        setBodyFirstCommandIndex(Long.parseLong(datalist.get(2).getString()));

        for(int i=3; i<datalist.getCount(); i++) {
            DataList dataCmd = datalist.get(i).getList();

            int command = Integer.parseInt(dataCmd.get(0).getString());
            int parameter = Integer.parseInt(dataCmd.get(1).getString());

            getCommands().add(new Command(command, parameter));
        }

        return true;
    }
    private boolean readConstants(DataList datalist, Procedure procedure)
            throws IOException {

        String listname = datalist.get(0).getString();
        if(!listname.equals("\"Const\"") && !listname.equals("\"DefPrm\""))
            return false;

        for(int i=2; i<datalist.getCount(); i++) {
            DataList dataConst = datalist.get(i).getList();

            String type = dataConst.get(0).getString();
            type = type.substring(1, type.length()-1);

            String value = null;
            if(dataConst.getCount()>1)
                value = dataConst.get(1).getString();

            if(type.equals("S"))
                value = value.substring(1, value.length()-1);

            Constant const_ = new Constant(type, value);
            if(procedure!=null)
                procedure.getDefinedParameters().add(const_);
            else
                getConstants().add(const_);
        }

        return true;
    }
    private boolean readVariables(DataList datalist, Procedure procedure)
            throws IOException {

        String listname = datalist.get(0).getString();
        if(!listname.equals("\"Var\""))
            return false;

        for(int i=2; i<datalist.getCount(); i++) {
            DataList dataVar = datalist.get(i).getList();

            String name = dataVar.get(0).getString();
            name = name.substring(1, name.length()-1);

            int options = Integer.parseInt(dataVar.get(1).getString());
            int reserved0 = Integer.parseInt(dataVar.get(2).getString());

            Variable var = new Variable(name, options, reserved0);
            if(procedure!=null)
                procedure.getVariables().add(var);
            else
                getVariables().add(var);
        }

        return true;
    }
    private boolean readLbls(DataList datalist, Procedure procedure)
            throws IOException {

        String listname = datalist.get(0).getString();
        if(!listname.equals("\"Lbl\""))
            return false;

        for(int i=2; i<datalist.getCount(); i++) {
            DataList dataLbl = datalist.get(i).getList();

            String name = dataLbl.get(0).getString();
            name = name.substring(1, name.length()-1);

            int cmdIndex = Integer.parseInt(dataLbl.get(1).getString());

            Label lbl = new Label(name, cmdIndex);
            if(procedure!=null)
                procedure.getLabels().add(lbl);
            else
                getLabels().add(lbl);
        }

        return true;
    }
    private boolean readProcedures(DataList datalist)
            throws IOException {

        String listname = datalist.get(0).getString();
        if(!listname.equals("\"Proc\""))
            return false;

        for(int i=2; i<datalist.getCount(); i++) {
            DataList dataProc = datalist.get(i).getList();

            String name = dataProc.get(0).getString();
            name = name.substring(1, name.length()-1);

            int options = Integer.parseInt(dataProc.get(1).getString());
            int prmCount = Integer.parseInt(dataProc.get(2).getString());
            int firstCmdIndex = Integer.parseInt(dataProc.get(3).getString());

            Procedure proc = new Procedure(name, options, prmCount, firstCmdIndex);
            getProcedures().add(proc);

            int position = 4;
            if(position<dataProc.getCount() && readLbls(dataProc.get(position).getList(), proc))
                position++;
            if(position<dataProc.getCount() && readVariables(dataProc.get(position).getList(), proc))
                position++;
            if(position<dataProc.getCount() && readConstants(dataProc.get(position).getList(), proc))
                position++;

            if(position!=dataProc.getCount())
                throw new IOException("Wrong data format");
        }

        return true;
    }

    private SourceBlock disassembleBlock(int blockBegin, int blockEnd, Procedure proc, boolean canReturnValue)
            throws IOException {

        SourceBlock block = new SourceBlock();
        List<String> stack = new ArrayList<String>(64);

        List<Label> lstLbl = proc!=null ? proc.getLabels() : getLabels();
        
        for(int position=blockBegin, step; position<=blockEnd; position+=step) {
            //if(position==1255)
            //    System.out.println(position);

            // Checking labels
            for(Label lbl : lstLbl)
                if(lbl.getCommandIndex()==position)
                    block.addLine(lbl.getName()+":");

            step = disassebleCommand(block, stack, proc, blockBegin, blockEnd, position);
        }

        if(canReturnValue && stack.size()==1) {
            if(block.getLines().isEmpty())
                block.addLine(makeSourceString(stack.remove(0)));
            else if(block.getLines().size()==1)
                block.insertLine(0, makeSourceString(stack.remove(0)));
        }
        if(stack.size()>0)
            throw new IOException("Stack not empty at position "+blockEnd);
        
        return block;
    }
    private int disassebleCommand(SourceBlock block, List<String> stack, Procedure proc, int blockBegin, int blockEnd, int position)
            throws IOException {

        int step = 1;
        Command cmd = getCommands().get(position);
        int command = cmd.getCommand();
        int parameter = cmd.getParameter();

        switch(command) {
            case 1: // Setting source line number
                break;
            case 2: // Loading global variable. Parameter - index of global variable.
                stack.add(getVariables().get(parameter).getName());
                break;
            case 3: // Loading local variable. Parameter - index of local variable.
                stack.add(proc.getVariables().get(parameter).getName());
                break;
            case 4: // Loading global constant. Parameter - index of global constant.
                stack.add(getConstantValue(getConstants().get(parameter)));
                break;
            case 5: // Loading result of function. Parameter = 0.
                if(parameter!=0)
                    throw new IOException("Parameter is not 0");
                break;
            case 6: // Loading False. Parameter = 0.
                if(parameter!=0)
                    throw new IOException("Parameter is not 0");
                String false6 = getDictionary().getString("false");
                stack.add(false6);
                break;
            case 7: // Loading True. Parameter = 0.
                if(parameter!=0)
                    throw new IOException("Parameter is not 0");
                String true7 = getDictionary().getString("true");
                stack.add(true7);
                break;
            case 8: // Loading Undefined. Parameter = 0.
                if(parameter!=0)
                    throw new IOException("Parameter is not 0");
                String undefined8 = getDictionary().getString("undefined");
                stack.add(undefined8);
                break;
            case 9: // Loading Null. Parameter = 0.
                if(parameter!=0)
                    throw new IOException("Parameter is not 0");
                String null9 = getDictionary().getString("null");
                stack.add(null9);
                break;
            case 10: // Loading empty value. Parameter = 0.
                if(parameter!=0)
                    throw new IOException("Parameter is not 0");
                stack.add("");
                break;
            case 12: // Getting property of object. Parameter - index in Const
                String field12 = getConstantValue(getConstants().get(parameter));
                field12 = field12.substring(1, field12.length()-1);
                String object12 = stack.remove(stack.size()-1);
                String result12 = object12+"."+field12;
                stack.add(result12);
                break;
            case 13: // Getting value by index
                String index13 = stack.remove(stack.size()-1);
                String object13 = stack.remove(stack.size()-1);
                String result13 = object13+"["+index13+"]";
                stack.add(result13);
                break;
            case 14: // Get iterator
                break;
            case 15: // Is iterator has next?
                break;
            case 16: // Saving to variable. Parameter = 0.
                if(parameter!=0)
                    throw new IOException("Parameter is not 0");
                if(stack.size()!=2)
                    throw new IOException("Wrong stack size");
                String expr16 = stack.remove(stack.size()-1);
                String var16 = stack.remove(stack.size()-1);
                String result16 = makeSourceString(var16+"="+expr16+";");
                block.addLine(result16);
                break;
            case 17: // Saving to function result. Parameter = 0.
                if(parameter!=0)
                    throw new IOException("Parameter is not 0");
                if(stack.size()!=1)
                    throw new IOException("Wrong stack size");
                if(position+1>blockEnd || getCommands().get(position+1).getCommand()!=45)
                    throw new IOException("Wrong next command");
                break;
            case 18: // Setting number of parameters
                String params18 = "";
                if(parameter>0) {
                    for(int i=0; i<parameter; i++)
                        params18 = ","+stack.remove(stack.size()-1)+params18;
                    params18 = params18.substring(1);
                }
                stack.add(params18);
                break;
            case 19: // Calling method from Proc. Parameter - index in Proc
                String method19 = getProcedures().get(parameter).getName();
                String params19 = stack.remove(stack.size()-1);
                String result19 = method19+"("+params19+")";
                boolean finished19 = true;
                if(position+1<=blockEnd) {
                    Command nextCmd = getCommands().get(position+1);
                    if(nextCmd.getCommand()==5)
                        finished19 = false;
                }
                if(finished19) {
                    result19 = makeSourceString(result19+";");
                    block.addLine(result19);
                } else
                    stack.add(result19);
                break;
            case 20: // Calling full-named procedure. Parameter - index in Const
                String method20 = getConstantValue(getConstants().get(parameter));
                method20 = method20.substring(1, method20.length()-1);
                String params20 = stack.remove(stack.size()-1);
                String context20 = stack.remove(stack.size()-1);
                String result20 = makeSourceString(context20+"."+method20+"("+params20+");");
                block.addLine(result20);
                break;
            case 21: // Calling full-named function. Parameter - index in Const
                String method21 = getConstantValue(getConstants().get(parameter));
                method21 = method21.substring(1, method21.length()-1);
                String params21 = stack.remove(stack.size()-1);
                String context21 = stack.remove(stack.size()-1);
                String result21 = context21+"."+method21+"("+params21+")";
                boolean finished21 = true;
                if(position+1<=blockEnd) {
                    Command nextCmd = getCommands().get(position+1);
                    if(nextCmd.getCommand()==5)
                        finished21 = false;
                }
                if(finished21) {
                    result21 = makeSourceString(result21+";");
                    block.addLine(result21);
                } else
                    stack.add(result21);
                break;
            case 22: // Ending the subprogram
                break;
            case 23: // Operator unary -
                String expr23 = stack.remove(stack.size()-1);
                String result23 = "(-"+expr23+")";
                stack.add(result23);
                break;
            case 24: // Operator +
                String exprRight24 = stack.remove(stack.size()-1);
                String exprLeft24 = stack.remove(stack.size()-1);
                String result24 = "("+exprLeft24+"+"+exprRight24+")";
                stack.add(result24);
                break;
            case 25: // Operator -
                String exprRight25 = stack.remove(stack.size()-1);
                String exprLeft25 = stack.remove(stack.size()-1);
                String result25 = "("+exprLeft25+"-"+exprRight25+")";
                stack.add(result25);
                break;
            case 26: // Operator *
                String exprRight26 = stack.remove(stack.size()-1);
                String exprLeft26 = stack.remove(stack.size()-1);
                String result26 = "("+exprLeft26+"*"+exprRight26+")";
                stack.add(result26);
                break;
            case 27: // Operator /
                String exprRight27 = stack.remove(stack.size()-1);
                String exprLeft27 = stack.remove(stack.size()-1);
                String result27 = "("+exprLeft27+"/"+exprRight27+")";
                stack.add(result27);
                break;
            case 29: // Operator Not
                if(parameter!=0)
                    throw new IOException("Unexpected value of parameter");
                String expr29 = stack.remove(stack.size()-1);
                String not29 = getDictionary().getString("not");
                String result29 = "("+not29+" "+expr29+")";
                stack.add(result29);
                break;
            case 30: // Operator And (beginnig part). Parameter - index of cmd when false
                String and30 = getDictionary().getString("and");
                stack.add(and30);
                break;
            case 31: // Operator Or (beginnig part). Parameter - index of cmd when true
                String or31 = getDictionary().getString("or");
                stack.add(or31);
                break;
            case 33: // Operator = (compare)
                if(parameter!=0)
                    throw new IOException("Unexpected value of parameter");
                String exprRight33 = stack.remove(stack.size()-1);
                String exprLeft33 = stack.remove(stack.size()-1);
                String result33 = "("+exprLeft33+"="+exprRight33+")";
                stack.add(result33);
                break;
            case 34: // Operator <>
                if(parameter!=0)
                    throw new IOException("Unexpected value of parameter");
                String exprRight34 = stack.remove(stack.size()-1);
                String exprLeft34 = stack.remove(stack.size()-1);
                String result34 = "("+exprLeft34+"<>"+exprRight34+")";
                stack.add(result34);
                break;
            case 35: // Operator >
                if(parameter!=0)
                    throw new IOException("Unexpected value of parameter");
                String exprRight35 = stack.remove(stack.size()-1);
                String exprLeft35 = stack.remove(stack.size()-1);
                String result35 = "("+exprLeft35+">"+exprRight35+")";
                stack.add(result35);
                break;
            case 36: // Operator <
                if(parameter!=0)
                    throw new IOException("Unexpected value of parameter");
                String exprRight36 = stack.remove(stack.size()-1);
                String exprLeft36 = stack.remove(stack.size()-1);
                String result36 = "("+exprLeft36+"<"+exprRight36+")";
                stack.add(result36);
                break;
            case 37: // Operator >=
                if(parameter!=0)
                    throw new IOException("Unexpected value of parameter");
                String exprRight37 = stack.remove(stack.size()-1);
                String exprLeft37 = stack.remove(stack.size()-1);
                String result37 = "("+exprLeft37+">="+exprRight37+")";
                stack.add(result37);
                break;
            case 38: // Operator <=
                if(parameter!=0)
                    throw new IOException("Unexpected value of parameter");
                String exprRight38 = stack.remove(stack.size()-1);
                String exprLeft38 = stack.remove(stack.size()-1);
                String result38 = "("+exprLeft38+"<="+exprRight38+")";
                stack.add(result38);
                break;
            case 39: // jump
                boolean isEnded39 = false;
                if(position-2>=blockBegin) {
                    Command prevCmd1 = getCommands().get(position-1);
                    Command prevCmd2 = getCommands().get(position-2);
                    if(prevCmd1.getCommand()==45 && prevCmd2.getCommand()==17)
                        isEnded39 = true;
                }
                if(isEnded39) {
                    String expr39 = stack.remove(stack.size()-1);
                    String return39 = getDictionary().getString("return");
                    String result39 = makeSourceString(return39+" "+expr39+";");
                    block.addLine(result39);
                } else
                    block.addLine("", parameter);
                break;
            case 40: // Block If Parameter - index of first cmd of Else
                String expr40 = stack.remove(stack.size()-1);
                SourceBlock blockIf40 = disassembleBlock(position+1, parameter-1, proc, true);
                blockIf40.removeLastLine();
                SourceBlock blockElse40 = null;
                if(blockIf40.getLastJump()>parameter)
                    blockElse40 = disassembleBlock(parameter, blockIf40.getLastJump()-1, proc, true);
                if(blockElse40!=null
                        && blockIf40.getLines().size()==1
                        && blockIf40.getLines().get(0).getString().length()>0
                        && blockIf40.getLines().get(0).getString().charAt(blockIf40.getLines().get(0).getString().length()-1)!=';'
                        && blockElse40.getLines().size()==1
                        && blockElse40.getLines().get(0).getString().length()>0
                        && blockElse40.getLines().get(0).getString().charAt(blockElse40.getLines().get(0).getString().length()-1)!=';') { // Short
                    String result40 = "?("+expr40
                            +","+blockIf40.getLines().get(0)
                            +","+blockElse40.getLines().get(0)
                            +")";
                    stack.add(result40);
                    step = blockIf40.getLastJump()-position;
                } else if(blockElse40==null && blockIf40.getLastJump()<position) { // Cycle
                    int lineCount = block.getLines().size();
                    String lineStrM1 = null;
                    if(lineCount>=1)
                        lineStrM1 = block.getLines().get(lineCount-1).getString();
                    String lineStrM2 = null;
                    if(lineCount>=2)
                        lineStrM2 = block.getLines().get(lineCount-2).getString();
                    if(parameter<=blockEnd && getCommands().get(parameter).getCommand()==50) {
                        if(lineCount>=2
                                && lineStrM2.matches(".+?=.+;$")
                                && lineStrM1.matches("=.+;$")) {
                            String param1 = lineStrM2.substring(0, lineStrM2.length()-1);
                            String param2 = lineStrM1.substring(1, lineStrM1.length()-1);
                            String for40 = getDictionary().getString("for");
                            String to40 = getDictionary().getString("to");
                            String do40 = getDictionary().getString("do");
                            block.getLines().remove(lineCount-1);
                            block.getLines().remove(lineCount-2);
                            block.addLine(makeSourceString(for40+" "+param1+" "+to40+" "+param2+" "+do40));
                            step = parameter-position+1;
                        } else if(lineCount>=2 
                                && lineStrM2.matches("=.+;$")
                                && lineStrM1.matches("0.+?=;$")) {
                            String param1 = lineStrM1.substring(1, lineStrM1.length()-2);
                            String param2 = lineStrM2.substring(1, lineStrM2.length()-1);
                            String foreach40 = getDictionary().getString("foreach");
                            String in40 = getDictionary().getString("in");
                            String do40 = getDictionary().getString("do");
                            block.getLines().remove(lineCount-1);
                            block.getLines().remove(lineCount-2);
                            block.addLine(makeSourceString(foreach40+" "+param1+" "+in40+" "+param2+" "+do40));
                            blockIf40.getLines().remove(0);
                            blockIf40.getLines().remove(0);
                            step = parameter-position+1+3+3;
                        } else
                            throw new IOException("Wrong cycle format");
                    } else {
                        String while40 = getDictionary().getString("while");
                        String do40 = getDictionary().getString("do");
                        block.addLine(makeSourceString(while40+" "+expr40+" "+do40));
                        step = parameter-position;
                    }
                    blockIf40.checkJumps(position+1, parameter-1, true);
                    for(SourceBlock.Line line : blockIf40.getLines()) 
                        block.addLine(makeIndent(line.getString()), line.getCommandIndex());
                    String enddo40 = getDictionary().getString("enddo");
                    block.addLine(makeSourceString(enddo40+";"));
                } else { // If Else EndIf
                    String if40 = getDictionary().getString("if");
                    String then40 = getDictionary().getString("then");
                    block.addLine(makeSourceString(if40+" "+expr40+" "+then40));
                    for(SourceBlock.Line line : blockIf40.getLines())
                        block.addLine(makeIndent(line.getString()), line.getCommandIndex());
                    if(blockElse40!=null) {
                        String else40 = getDictionary().getString("else");
                        block.addLine(makeSourceString(else40));
                        for(SourceBlock.Line line : blockElse40.getLines())
                            block.addLine(makeIndent(line.getString()), line.getCommandIndex());
                    }
                    String endif40 = getDictionary().getString("endif");
                    block.addLine(makeSourceString(endif40+";"));
                    step = blockIf40.getLastJump()-position;
                }
                break;
            case 42: // Operator Goto. Parameter - index of label
                List<Label> lstLbl42 = proc!=null ? proc.getLabels() : getLabels();
                String lbl42 = lstLbl42.get(parameter).getName();
                String goto42 = getDictionary().getString("goto");
                String result42 = makeSourceString(goto42+" "+lbl42+";");
                block.addLine(result42);
                break;
            case 43: // Cycle
                stack.remove(stack.size()-1);
                break;
            case 44: // Block Try Parameter - index of first cmd of Catch
                if(!stack.isEmpty())
                    throw new IOException("Wrong stack size");
                SourceBlock blockTry44 = disassembleBlock(position+1, parameter-1, proc, false);
                blockTry44.removeLastLine();
                SourceBlock blockCatch44 = disassembleBlock(parameter, blockTry44.getLastJump()-1, proc, false);
                String try44 = getDictionary().getString("try");
                block.addLine(makeSourceString(try44));
                for(SourceBlock.Line line : blockTry44.getLines())
                    block.addLine(makeIndent(line.getString()), line.getCommandIndex());
                String except44 = getDictionary().getString("except");
                block.addLine(except44);
                for(SourceBlock.Line line : blockCatch44.getLines())
                    block.addLine(makeIndent(line.getString()), line.getCommandIndex());
                String endtry44 = getDictionary().getString("endtry");
                block.addLine(makeSourceString(endtry44+";"));
                step = blockCatch44.getLastJump()-position;
                break;
            case 45: // Operator Return. Beginig part
                break;
            case 46: // End of block Try
                block.setLastJump(position+1);
                break;
            case 47: // Operator RaiseException
                String result47 = getDictionary().getString("raise");
                if(parameter==1) {
                    String expr47 = stack.remove(stack.size()-1);
                    result47 += " "+expr47;
                }
                result47 = makeSourceString(result47+";");
                block.addLine(result47);
                break;
            case 48: // Cycle begin
                break;
            case 49: // Cycle vaiable
                stack.add("");
                break;
            case 50: // Cycle end
                break;
            case 51: // Creating new object with New. Parameter - index in Const, name of object type
                String objecttype51 = getConstantValue(getConstants().get(parameter));
                objecttype51 = objecttype51.substring(1, objecttype51.length()-1);
                String params51 = stack.remove(stack.size()-1);
                String new51 = getDictionary().getString("new");
                String result51 = new51+" "+objecttype51+"("+params51+")";
                stack.add(result51);
                break;
            case 52: // Operator Execute. Parameter=0
                if(stack.size()!=1)
                    throw new IOException("Wrong stack size");
                String params52 = stack.remove(stack.size()-1);
                String execute52 = getDictionary().getString("execute");
                String result52 = makeSourceString(execute52+" "+params52+";");
                block.addLine(result52);
                break;
            case 53:
                String expr53 = stack.remove(stack.size()-1);
                String strlen53 = getDictionary().getString("strlen");
                String result53 = strlen53+"("+expr53+")";
                stack.add(result53);
                break;
            case 54:
                String expr54 = stack.remove(stack.size()-1);
                String triml54 = getDictionary().getString("triml");
                String result54 = triml54+"("+expr54+")";
                stack.add(result54);
                break;
            case 55:
                String expr55 = stack.remove(stack.size()-1);
                String trimr55 = getDictionary().getString("trimr");
                String result55 = trimr55+"("+expr55+")";
                stack.add(result55);
                break;
            case 56:
                String expr56 = stack.remove(stack.size()-1);
                String trimall56 = getDictionary().getString("trimall");
                String result56 = trimall56+"("+expr56+")";
                stack.add(result56);
                break;
            case 57:
                String pos57 = stack.remove(stack.size()-1);
                String expr57 = stack.remove(stack.size()-1);
                String left57 = getDictionary().getString("left");
                String result57 = left57+"("+expr57+","+pos57+")";
                stack.add(result57);
                break;
            case 58:
                String pos58 = stack.remove(stack.size()-1);
                String expr58 = stack.remove(stack.size()-1);
                String right58 = getDictionary().getString("right");
                String result58 = right58+"("+expr58+","+pos58+")";
                stack.add(result58);
                break;
            case 59:
                String len59 = stack.remove(stack.size()-1);
                String pos59 = stack.remove(stack.size()-1);
                String expr59 = stack.remove(stack.size()-1);
                String mid59 = getDictionary().getString("mid");
                String result59 = mid59+"("+expr59+","+pos59+","+len59+")";
                stack.add(result59);
                break;
            case 60:
                String substr60 = stack.remove(stack.size()-1);
                String expr60 = stack.remove(stack.size()-1);
                String find60 = getDictionary().getString("find");
                String result60 = find60+"("+expr60+","+substr60+")";
                stack.add(result60);
                break;
            case 61:
                String expr61 = stack.remove(stack.size()-1);
                String upper61 = getDictionary().getString("upper");
                String result61 = upper61+"("+expr61+")";
                stack.add(result61);
                break;
            case 62:
                String expr62 = stack.remove(stack.size()-1);
                String lower62 = getDictionary().getString("lower");
                String result62 = lower62+"("+expr62+")";
                stack.add(result62);
                break;
            case 63:
                String expr63 = stack.remove(stack.size()-1);
                String char63 = getDictionary().getString("char");
                String result63 = char63+"("+expr63+")";
                stack.add(result63);
                break;
            case 64:
                String pos64 = stack.remove(stack.size()-1);
                String expr64 = stack.remove(stack.size()-1);
                String charcode64 = getDictionary().getString("charcode");
                String result64 = charcode64+"("+expr64+","+pos64+")";
                stack.add(result64);
                break;
            case 65:
                String expr65 = stack.remove(stack.size()-1);
                String isblankstring65 = getDictionary().getString("isblankstring");
                String result65 = isblankstring65+"("+expr65+")";
                stack.add(result65);
                break;
            case 66:
                String expr66 = stack.remove(stack.size()-1);
                String int66 = getDictionary().getString("int");
                String result66 = int66+"("+expr66+")";
                stack.add(result66);
                break;
            case 67:
                String pos67 = stack.remove(stack.size()-1);
                String expr67 = stack.remove(stack.size()-1);
                String round67 = getDictionary().getString("round");
                String result67 = round67+"("+expr67+","+pos67+")";
                stack.add(result67);
                break;
            case 68:
                String type68 = stack.remove(stack.size()-1);
                String pos68 = stack.remove(stack.size()-1);
                String expr68 = stack.remove(stack.size()-1);
                String round68 = getDictionary().getString("round");
                String result68 = round68+"("+expr68+","+pos68+","+type68+")";
                stack.add(result68);
                break;
            case 69: // Logical operator ending part. Parameter=0
                if(parameter!=0)
                    throw new IOException("Unexpected value of parameter");
                String and69 = getDictionary().getString("and");
                String or69 = getDictionary().getString("or");
                if(stack.size()>=3 &&
                        (stack.get(stack.size()-2).equals(and69) || stack.get(stack.size()-2).equals(or69))) {
                    String exprRight69 = stack.remove(stack.size()-1);
                    String oper69 = stack.remove(stack.size()-1);
                    String exprLeft69 = stack.remove(stack.size()-1);
                    String result69 = "("+exprLeft69+" "+oper69+" "+exprRight69+")";
                    stack.add(result69);
                } else {
                    String expr69 = stack.remove(stack.size()-1);
                    String boolean69 = getDictionary().getString("boolean");
                    String result69 = boolean69+"("+expr69+")";
                    stack.add(result69);
                }
                break;
            case 70:
                String expr70 = stack.remove(stack.size()-1);
                String number70 = getDictionary().getString("number");
                String result70 = number70+"("+expr70+")";
                stack.add(result70);
                break;
            case 71:
                String expr71 = stack.remove(stack.size()-1);
                String string71 = getDictionary().getString("string");
                String result71 = string71+"("+expr71+")";
                stack.add(result71);
                break;
            case 72:
                String expr72 = stack.remove(stack.size()-1);
                String date72 = getDictionary().getString("date");
                String result72 = date72+"("+expr72+")";
                stack.add(result72);
                break;
            case 73:
                String day73 = stack.remove(stack.size()-1);
                String month73 = stack.remove(stack.size()-1);
                String year73 = stack.remove(stack.size()-1);
                String date73 = getDictionary().getString("date");
                String result73 = date73+"("+year73+","+month73+","+day73+")";
                stack.add(result73);
                break;
            case 74:
                String second74 = stack.remove(stack.size()-1);
                String minute74 = stack.remove(stack.size()-1);
                String hour74 = stack.remove(stack.size()-1);
                String day74 = stack.remove(stack.size()-1);
                String month74 = stack.remove(stack.size()-1);
                String year74 = stack.remove(stack.size()-1);
                String date74 = getDictionary().getString("date");
                String result74 = date74+"("+year74+","+month74+","+day74+","+hour74+","+minute74+","+second74+")";
                stack.add(result74);
                break;
            case 75:
                String month75 = stack.remove(stack.size()-1);
                String date75 = stack.remove(stack.size()-1);
                String addmonth75 = getDictionary().getString("addmonth");
                String result75 = addmonth75+"("+date75+","+month75+")";
                stack.add(result75);
                break;
            case 76:
                String date76 = stack.remove(stack.size()-1);
                String begofmonth76 = getDictionary().getString("begofmonth");
                String result76 = begofmonth76+"("+date76+")";
                stack.add(result76);
                break;
            case 77:
                String date77 = stack.remove(stack.size()-1);
                String endofmonth77 = getDictionary().getString("endofmonth");
                String result77 = endofmonth77+"("+date77+")";
                stack.add(result77);
                break;
            case 78:
                String date78 = stack.remove(stack.size()-1);
                String begofquarter78 = getDictionary().getString("begofquarter");
                String result78 = begofquarter78+"("+date78+")";
                stack.add(result78);
                break;
            case 79:
                String date79 = stack.remove(stack.size()-1);
                String endofquarter79 = getDictionary().getString("endofquarter");
                String result79 = endofquarter79+"("+date79+")";
                stack.add(result79);
                break;
            case 80:
                String date80 = stack.remove(stack.size()-1);
                String begofyear80 = getDictionary().getString("begofyear");
                String result80 = begofyear80+"("+date80+")";
                stack.add(result80);
                break;
            case 81:
                String date81 = stack.remove(stack.size()-1);
                String endofyear81 = getDictionary().getString("endofyear");
                String result81 = endofyear81+"("+date81+")";
                stack.add(result81);
                break;
            case 82:
                String date82 = stack.remove(stack.size()-1);
                String year82 = getDictionary().getString("year");
                String result82 = year82+"("+date82+")";
                stack.add(result82);
                break;
            case 83:
                String date83 = stack.remove(stack.size()-1);
                String month83 = getDictionary().getString("month");
                String result83 = month83+"("+date83+")";
                stack.add(result83);
                break;
            case 84:
                String date84 = stack.remove(stack.size()-1);
                String day84 = getDictionary().getString("day");
                String result84 = day84+"("+date84+")";
                stack.add(result84);
                break;
            case 85:
                String date85 = stack.remove(stack.size()-1);
                String hour85 = getDictionary().getString("hour");
                String result85 = hour85+"("+date85+")";
                stack.add(result85);
                break;
            case 86:
                String date86 = stack.remove(stack.size()-1);
                String minute86 = getDictionary().getString("minute");
                String result86 = minute86+"("+date86+")";
                stack.add(result86);
                break;
            case 87:
                String date87 = stack.remove(stack.size()-1);
                String second87 = getDictionary().getString("second");
                String result87 = second87+"("+date87+")";
                stack.add(result87);
                break;
            case 88:
                String date88 = stack.remove(stack.size()-1);
                String dayofyear88 = getDictionary().getString("dayofyear");
                String result88 = dayofyear88+"("+date88+")";
                stack.add(result88);
                break;
            case 90:
                String date90 = stack.remove(stack.size()-1);
                String dayofweek90 = getDictionary().getString("dayofweek");
                String result90 = dayofweek90+"("+date90+")";
                stack.add(result90);
                break;
            case 91:
                String date91 = stack.remove(stack.size()-1);
                String begofweek91 = getDictionary().getString("begofweek");
                String result91 = begofweek91+"("+date91+")";
                stack.add(result91);
                break;
            case 92:
                String date92 = stack.remove(stack.size()-1);
                String endofweek92 = getDictionary().getString("endofweek");
                String result92 = endofweek92+"("+date92+")";
                stack.add(result92);
                break;
            case 93:
                String date93 = stack.remove(stack.size()-1);
                String begofday93 = getDictionary().getString("begofday");
                String result93 = begofday93+"("+date93+")";
                stack.add(result93);
                break;
            case 94:
                String date94 = stack.remove(stack.size()-1);
                String endofday94 = getDictionary().getString("endofday");
                String result94 = endofday94+"("+date94+")";
                stack.add(result94);
                break;
            case 95:
                String date95 = stack.remove(stack.size()-1);
                String begofhour95 = getDictionary().getString("begofhour");
                String result95 = begofhour95+"("+date95+")";
                stack.add(result95);
                break;
            case 96:
                String date96 = stack.remove(stack.size()-1);
                String endofhour96 = getDictionary().getString("endofhour");
                String result96 = endofhour96+"("+date96+")";
                stack.add(result96);
                break;
            case 97:
                String date97 = stack.remove(stack.size()-1);
                String begofminute97 = getDictionary().getString("begofminute");
                String result97 = begofminute97+"("+date97+")";
                stack.add(result97);
                break;
            case 98:
                String date98 = stack.remove(stack.size()-1);
                String endofminute98 = getDictionary().getString("endofminute");
                String result98 = endofminute98+"("+date98+")";
                stack.add(result98);
                break;
            case 99:
                String currentdate99 = getDictionary().getString("currentdate");
                String result99 = currentdate99+"()";
                stack.add(result99);
                break;
            case 100:
                String repl100 = stack.remove(stack.size()-1);
                String fnd100 = stack.remove(stack.size()-1);
                String expr100 = stack.remove(stack.size()-1);
                String strreplace100 = getDictionary().getString("strreplace");
                String result100 = strreplace100+"("+expr100+","+fnd100+","+repl100+")";
                stack.add(result100);
                break;
            case 101:
                String expr101 = stack.remove(stack.size()-1);
                String strlinecount101 = getDictionary().getString("strlinecount");
                String result101 = strlinecount101+"("+expr101+")";
                stack.add(result101);
                break;
            case 102:
                String pos102 = stack.remove(stack.size()-1);
                String expr102 = stack.remove(stack.size()-1);
                String strgetline102 = getDictionary().getString("strgetline");
                String result102 = strgetline102+"("+expr102+","+pos102+")";
                stack.add(result102);
                break;
            case 103:
                String params103 = stack.remove(stack.size()-1);
                String min103 = getDictionary().getString("min");
                String result103 = min103+"("+params103+")";
                stack.add(result103);
                break;
            case 104:
                String params104 = stack.remove(stack.size()-1);
                String max104 = getDictionary().getString("max");
                String result104 = max104+"("+params104+")";
                stack.add(result104);
                break;
            case 105:
                String pos105 = stack.remove(stack.size()-1);
                String expr105 = stack.remove(stack.size()-1);
                String stroccurencecount105 = getDictionary().getString("stroccurencecount");
                String result105 = stroccurencecount105+"("+expr105+","+pos105+")";
                stack.add(result105);
                break;
            case 106:
                String errordescription106 = getDictionary().getString("errordescription");
                String result106 = errordescription106+"()";
                stack.add(result106);
                break;
            case 107:
                String expr107 = stack.remove(stack.size()-1);
                String typeof107 = getDictionary().getString("typeof");
                String result107 = typeof107+"("+expr107+")";
                stack.add(result107);
                break;
            case 108:
                String expr108 = stack.remove(stack.size()-1);
                String type108 = getDictionary().getString("type");
                String result108 = type108+"("+expr108+")";
                stack.add(result108);
                break;
            case 109:
                String expr109 = stack.remove(stack.size()-1);
                String eval109 = getDictionary().getString("eval");
                String result109 = eval109+"("+expr109+")";
                stack.add(result109);
                break;
            case 110:
                String frmt110 = stack.remove(stack.size()-1);
                String expr110 = stack.remove(stack.size()-1);
                String format110 = getDictionary().getString("format");
                String result110 = format110+"("+expr110+","+frmt110+")";
                stack.add(result110);
                break;
            case 111:
                String frmt111 = stack.remove(stack.size()-1);
                String expr111 = stack.remove(stack.size()-1);
                String new111 = getDictionary().getString("new");
                String result111 = new111+"("+expr111+","+frmt111+")";
                stack.add(result111);
                break;
            case 112:
                String expr112 = stack.remove(stack.size()-1);
                String result112 = "ACos"+"("+expr112+")";
                stack.add(result112);
                break;
            case 113:
                String expr113 = stack.remove(stack.size()-1);
                String result113 = "ASin"+"("+expr113+")";
                stack.add(result113);
                break;
            case 114:
                String expr114 = stack.remove(stack.size()-1);
                String result114 = "ATan"+"("+expr114+")";
                stack.add(result114);
                break;
            case 115:
                String expr115 = stack.remove(stack.size()-1);
                String result115 = "Cos"+"("+expr115+")";
                stack.add(result115);
                break;
            case 116:
                String expr116 = stack.remove(stack.size()-1);
                String result116 = "Exp"+"("+expr116+")";
                stack.add(result116);
                break;
            case 117:
                String expr117 = stack.remove(stack.size()-1);
                String result117 = "Log"+"("+expr117+")";
                stack.add(result117);
                break;
            case 118:
                String expr118 = stack.remove(stack.size()-1);
                String result118 = "Log10"+"("+expr118+")";
                stack.add(result118);
                break;
            case 119:
                String expr119 = stack.remove(stack.size()-1);
                String base119 = stack.remove(stack.size()-1);
                String result119 = "Pow"+"("+base119+","+expr119+")";
                stack.add(result119);
                break;
            case 120:
                String expr120 = stack.remove(stack.size()-1);
                String result120 = "Sin"+"("+expr120+")";
                stack.add(result120);
                break;
            case 121:
                String expr121 = stack.remove(stack.size()-1);
                String result121 = "Sqrt"+"("+expr121+")";
                stack.add(result121);
                break;
            case 122:
                String expr122 = stack.remove(stack.size()-1);
                String result122 = "Tan"+"("+expr122+")";
                stack.add(result122);
                break;
            case 124:
                if(stack.size()!=4)
                    throw new IOException("Wrong stack size");
                String listener124 = stack.remove(stack.size()-1);
                String listenerObject124 = stack.remove(stack.size()-1);
                String event124 = stack.remove(stack.size()-1);
                String eventObject124 = stack.remove(stack.size()-1);
                String addhandler124 = getDictionary().getString("addhandler");
                String result124 = makeSourceString(addhandler124+" "+eventObject124+"."+event124+","+listenerObject124+"."+listener124+";");
                block.addLine(result124);
                break;
            case 126:
                if(stack.size()!=4)
                    throw new IOException("Wrong stack size");
                String listener126 = stack.remove(stack.size()-1);
                String listenerObject126 = stack.remove(stack.size()-1);
                String event126 = stack.remove(stack.size()-1);
                String eventObject126 = stack.remove(stack.size()-1);
                String removehandler126 = getDictionary().getString("removehandler");
                String result126 = makeSourceString(removehandler126+" "+eventObject126+"."+event126+","+listenerObject126+"."+listener126+";");
                block.addLine(result126);
                break;
            case 127:
                String expr127 = stack.remove(stack.size()-1);
                String title127 = getDictionary().getString("title");
                String result127 = title127+"("+expr127+")";
                stack.add(result127);
            case 128:
                String errorinfo128 = getDictionary().getString("errorinfo");
                String result128 = errorinfo128+"()";
                stack.add(result128);
            default:
                throw new IOException("Unknown command at "+position);
        }

        return step;
    }

    private String getConstantValue(Constant constant)
            throws IOException {

        String type = constant.getType();
        String value = null;

        if(type.equals("N") || type.equals("#"))
            value = constant.getValue();
        else if(type.equals("B"))
            value = getDictionary().getString((constant.getValue().equals("0") ? "false" : "true"));
        else if(type.equals("D"))
            value = "'"+constant.getValue()+"'";
        else if(type.equals(""))
            value = "";
        else if(type.equals("L"))
            value = getDictionary().getString("null");
        else if(type.equals("U"))
            value = getDictionary().getString("undefined");
        else if(type.equals("S"))
            value = "\""+constant.getValue()+"\"";
        else
            throw new IOException("Unknown type: "+type);

        return value;
    }

    private String makeSourceString(String str) {
        return str.replace(STRING_LINE_FEED, STRING_LINE_FEED+"|");
    }
    private String makeIndent(String str) {
        return STRING_LINE_INDENT+str.replace(STRING_LINE_FEED, STRING_LINE_FEED+STRING_LINE_INDENT);
    }

    //--------------------------------------------------------------------------
}
